package com.gg.core;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;

import javax.jdo.JDOObjectNotFoundException;
import javax.jdo.PersistenceManager;

@SuppressWarnings("unchecked")
public class BaseDao<T extends BaseEntity, ID extends Serializable> {
	private Class<T> clazz;

	public BaseDao() {
		this.clazz = (Class<T>) ((ParameterizedType) getClass()
				.getGenericSuperclass()).getActualTypeArguments()[0];
	}

	public T saveOrUpdate(final T entity) {
		PersistenceManager pm = getPersistenceManager();
		// pm.setDetachAllOnCommit(true);
		try {
			return pm.makePersistent(entity);
		} finally {
			pm.close();
		}
	}

	public T getById(final ID id) {
		if (id == null) {
			return null;
		}
		PersistenceManager pm = getPersistenceManager();
		T entity;
		try {
			entity = (T) pm.getObjectById(clazz, id);
		} catch (JDOObjectNotFoundException e) {
			entity = null;
		} catch (IllegalArgumentException e) {
			entity = null;
		} finally {
			pm.close();
		}
		return entity;
	}

	public List<T> select(String query, Object[] params) {
		List<T> result;
		PersistenceManager pm = getPersistenceManager();
		pm.setDetachAllOnCommit(true);
		try {
			result = (List<T>) pm.newQuery(query).executeWithArray(params);
		} finally {
			pm.close();
		}

		return result;
	}

	public List<T> select() {
		List<T> result;
		PersistenceManager pm = getPersistenceManager();
		pm.setDetachAllOnCommit(true);
		try {
			result = copy((List<T>) pm.newQuery(
					"select from " + clazz.getName()).execute());
		} finally {
			pm.close();
		}

		return result;
	}

	protected PersistenceManager getPersistenceManager() {
		return PMF.get().getPersistenceManager();
	}

	protected <E> List<E> copy(final List<E> list) {
		List<E> result = new ArrayList<E>();
		result.addAll(list);
		return result;
	}

	public Class<T> getClazz() {
		return clazz;
	}

	public void setClazz(Class<T> clazz) {
		this.clazz = clazz;
	}

}
